-- HolyItemsM
-- Created by chengb Nov/10/2015
-- 圣器模块

module("HolyItemsM", package.seeall);

-- 圣器配置表
local holyItemsTable = {};

-- 所有的圣器编号
local holyItemsList = {};

-- 内部函数声明
local whenLeaveDungeon;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    holyItemsTable = {};

    local holy_items_CSV = get_holy_items_CSV();
    for i = 1, #holy_items_CSV do
        local id = holy_items_CSV[i].class_id;
        holyItemsTable[id] = holy_items_CSV[i];
    end

    holy_items_CSV = {};

    holyItemsList = table.keys(holyItemsTable);
    table.sort(holyItemsList);
end

-- 初始化
function init()
    loadCsv();

    EventMgr.removeAll("HolyItemsM");

    -- 关注玩家离开迷宫的事件
    EventMgr.register("HolyItemsM", event.LEAVE_DUNGEON, function()
        whenLeaveDungeon();
    end);
end

-- 检索配置
function query(classId, path)
    local m = holyItemsTable[classId];
    if m == nil then
        return nil;
    end
    if (path == "" or path == nil) then
        return m;
    else
        return m[path];
    end
end

-- 玩家离开迷宫的回调
whenLeaveDungeon = function()
    if ME.user.dbase:query("holy_items_level") ~= nil then
        -- 移除圣器数据
        ME.user.dbase:delete("holy_items_level");
    end

    if ME.user.dbase:query("holy_items_fail_record") ~= nil then
        -- 移除圣器升级失败记录
        ME.user.dbase:delete("holy_items_fail_record");
    end
end

-- 是否是圣器
function isHolyItems(classId, holyType)
    if holyType then
        return query(classId, "type") == holyType;
    end

    return query(classId) ~= nil;
end

-- 获取所有的圣器编号
function getAllHolyItems()
    return holyItemsList;
end

-- 获取德古拉城堡的圣器编号
function getDungeonHolyItems()
    -- 判断是否用于德古拉城堡
    local dungeonHolyItems = {};
    for _, c in pairs(holyItemsList) do
        if 1 == query(c, "is_holy") then
            table.insert(dungeonHolyItems, c);
        end
    end

    return dungeonHolyItems;
end

-- 获取圣器的基础等级
function getBaseLevel(classId)
    local baseLevelInfo = ME.user.dbase:query("holy_items_level", "base", {});
    return baseLevelInfo[classId] or 0;
end

-- 获取圣器的附加等级
function getExtraLevel(classId)
    local extraLevelInfo = ME.user.dbase:query("holy_items_level", "extra", {});
    return extraLevelInfo[classId] or 0;
end

--------------------------
-- 获取圣器的特殊属性
-- @param classId 圣器编号
-- @param level   特殊属性的等级（注：一般情况下不需要传入该参数，只有当等级为0时，为获取下一级描述需要传入）
function getExtraProps(classId, level)
    local effect = query(classId, "effect");
    if effect == nil or effect == "" then
        -- 没有配置特殊属性
        return {};
    end

    if type(effect) == "table" then
        return effect;
    end

    if type(effect) == "string" then
        -- 配置了公式
        local formuaName = effect;
        local args = query(classId, "effect_args") or {};
        return FormulaM.invoke(formuaName, ME.user, classId, args, level);
    end

    return {};
end

-- 获取圣器的特殊属性描述
function getExtraPropDesc(classId)
    local desc;
    local propDesc = query(classId, "prop_desc");
    if type(propDesc) == "string" and propDesc ~= "" then
        -- 配置了特殊属性的描述
        desc = propDesc;

        -- 获取特殊属性等级（0级时取1级的描述）
        local level = getExtraLevel(classId);
        local level = math.max(level, 1);
        local para = query(classId, "prop_desc_para");
        if type(para) == "table" and #para > 0 then
            local paraNum = #para;
            for i = 1, paraNum do
                local dummy = "{" .. i - 1 .. "}";
                local m = para[i];
                if type(m) ~= 'table' or m[level] == nil then
                    assert(false, "圣器(%d)的prop_desc_para字段配置错误", classId);
                end
                desc = string.gsub(desc, dummy, m[level]);
            end
        end
    else
        -- 没有配置特殊描述，默认取属性描述
        -- 获取特殊属性等级（0级时取1级的描述）
        local level = getExtraLevel(classId);
        local level = math.max(level, 1);
        local extraProps = getExtraProps(classId, level);
        desc = EquipM.getEquipPropDesc(extraProps, classId);
    end

    return desc;
end

-- 计算升级基础属性的消耗
function calcUpgradeBaseLevelCost(classId)
    -- 获取基础属性等级
    local level = getBaseLevel(classId);
    return FormulaM.invoke("CALC_HOLY_ITEMS_BASE_UPGRADE_COST", classId, level);
end

-- 计算升级特殊属性的消耗
function calcUpgradeExtraLevelCost(classId)
    -- 获取特殊属性等级
    local level = getBaseLevel(classId);
    return FormulaM.invoke("CALC_HOLY_ITEMS_EXTRA_UPGRADE_COST", classId, level);
end

-- 升级圣器基础属性
function upgradeBaseLevel(classId)
    local maxLevel = query(classId, "max_base_level");

    assert(type(maxLevel) == "number", "必须配置 max_base_level 字段");

    local baseLevelInfo = ME.user.dbase:query("holy_items_level", "base", {});
    local curLevel = baseLevelInfo[classId] or 0;
    if curLevel >= maxLevel then
        trace("HolyItemsM", "圣器(%d)基础等级已达最高等级。", classId);
        return false;
    end

    -- 检查消耗
    local cost = calcUpgradeBaseLevelCost(classId);
    if cost[1] == 1 then
        local itemId = cost[2];
        local amount = cost[3];
        local curAmount = ItemM.getAmount(ME.user, itemId);
        if curAmount < amount then
            trace("HolyItemsM", "无法升级圣器基础属性，物品(%d)数量不足", itemId);
            return false;
        end

        -- 扣除物品
        ItemM.costAmount(ME.user, itemId, amount);
    else
        assert(false, "暂不支持的消耗类型");
    end

    -- 判断是否成功
    local isSucc = FormulaM.invoke("IS_HOLY_ITEMS_UPGRADE_SUCC", ME.user, classId);
    if isSucc then
        -- 提升等级
        baseLevelInfo[classId] = curLevel + 1;
        ME.user.dbase:set("holy_items_level", "base", baseLevelInfo);

        local msg = string.format("[HolyItemsM]圣器(%d)的基础属性等级提升为(%d)", classId, baseLevelInfo[classId]);
        DungeonLogM.addLog(msg);

        -- 如果该圣器穿在身上，刷新一下附加属性
        if EquipM.isEquiped(classId) then
            PropM.refresh(ME.user);
        end

        -- 血契专属
        local prop = PropM.combine(ME.user, "hunter", 1);
        if prop[3] > 0 and classId == 8124 then
            -- 触发特技发动事件
            EventMgr.fire(event.SPECIAL_SKILL_TRIGGER, { propId = prop[1] });
        end

        -- 重置连续失败的次数
        resetFailTimes(classId);
    else
        -- 失败了
        -- 记录连续失败的次数
        recordFailTimes(classId);
    end

    -- 抛出事件
    EventMgr.fire(event.HOLY_ITEMS_IMPROVE, {
        ["classId"]     = classId,
        ["upgradeType"] = "base",
        ["level"]       = baseLevelInfo[classId],
        ["isSucc"]      = isSucc,
    });

    return true;
end

-- 升级圣器附加属性
function upgradeExtraLevel(classId)
    local maxLevel = query(classId, "max_extra_level");

    assert(type(maxLevel) == "number", "必须配置 max_extra_level 字段");

    local extraLevelInfo = ME.user.dbase:query("holy_items_level", "extra", {});
    local curLevel = extraLevelInfo[classId] or 0;
    if curLevel >= maxLevel then
        trace("HolyItemsM", "圣器(%d)附加等级已达最高等级。", classId);
        return false;
    end

    -- 判断基础属性等级是否达标
    local requireBaseLevel = FormulaM.invoke("CALC_HOLY_ITEMS_BASE_LEVEL_REQUIRE", classId, curLevel);
    local curBaseLevel = getBaseLevel(classId);
    if curBaseLevel < requireBaseLevel then
        trace("HolyItemsM", "无法升级圣器特殊升序，基础属性等级未达到要求，需求(%d)， 当前(%d)",
            requireBaseLevel, curBaseLevel);
        return false;
    end

    -- 检查消耗
    local cost = calcUpgradeExtraLevelCost(classId);
    if cost[1] == 1 then
        local itemId = cost[2];
        local amount = cost[3];
        local curAmount = ItemM.getAmount(ME.user, itemId);
        if curAmount < amount then
            trace("HolyItemsM", "无法升级圣器特殊属性，物品(%d)数量不足", itemId);
            return false;
        end

        -- 扣除物品
        ItemM.costAmount(ME.user, itemId, amount);
    else
        assert(false, "暂不支持的消耗类型");
    end

    -- 提升等级
    extraLevelInfo[classId] = curLevel + 1;
    ME.user.dbase:set("holy_items_level", "extra", extraLevelInfo);

    local msg = string.format("[HolyItemsM]圣器(%d)的附加属性等级提升为(%d)", classId, extraLevelInfo[classId]);
    DungeonLogM.addLog(msg);

    -- 如果该圣器穿在身上，刷新一下附加属性
    if EquipM.isEquiped(classId) then
        PropM.refresh(ME.user);
    end

    -- 抛出事件
    EventMgr.fire(event.HOLY_ITEMS_IMPROVE, {
        ["classId"]     = classId,
        ["upgradeType"] = "extra",
        ["level"]       = extraLevelInfo[classId],
        ["isSucc"]      = true,
    });

    -- 血契专属
    local prop = PropM.combine(ME.user, "hunter", 1);
    if prop[3] > 0 and classId == 8124 then
        -- 触发特技发动事件
        EventMgr.fire(event.SPECIAL_SKILL_TRIGGER, { propId = prop[1] });
    end

    return true;
end

-- 判断基础属性等级是否达到上限
function isBaseLevelMax(classId)
    local curLevel = getBaseLevel(classId);
    local maxLevel = HolyItemsM.query(classId, "max_base_level");
    return curLevel >= maxLevel;
end

-- 判断特殊属性等级是否达到上限
function isExtraLevelMax(classId)
    local curLevel = getExtraLevel(classId);
    local maxLevel = HolyItemsM.query(classId, "max_extra_level");
    return curLevel >= maxLevel;
end

-- 获取圣器的阶位
function getRank(classId)
    local baseLevel = getBaseLevel(classId);
    return FormulaM.invoke("CALC_HOLY_ITEMS_RANK", baseLevel);
end

-- 判断当前是否拥有圣器
function hasHolyItems()
    local holyItems = getAllHolyItems();
    for _, classId in pairs(holyItems) do
        if EquipM.hasEquipment(classId) then
            return true;
        end
    end

    return false;
end

-- 判断是否拥有所有的圣器
function isGaintAllHolyItems()
    local holyItems = getDungeonHolyItems();
    local isGainAll = true;
    for _, classId in pairs(holyItems) do
        if not EquipM.hasEquipment(classId) then
            isGainAll = false;
            break;
        end
    end

    return isGainAll;
end

-- 记录属性升级连续失败次数
function recordFailTimes(classId)
    local record = ME.user.dbase:query("holy_items_fail_record", {});
    if not record[classId] then
        record[classId] = 0;
    end

    record[classId] = record[classId] + 1;
    ME.user.dbase:set("holy_items_fail_record", record);

    printTable(record, "圣器属性升级失败记录");
end

-- 重置连续失败次数
function resetFailTimes(classId)
    local record = ME.user.dbase:query("holy_items_fail_record", {});
    if not record[classId] then
        return;
    end

    record[classId] = 0;
    ME.user.dbase:set("holy_items_fail_record", record);
end

-- 获取连续失败次数
function getFailTimes(classId)
    local record = ME.user.dbase:query("holy_items_fail_record", {});
    if not record[classId] then
        return 0;
    end
    return record[classId];
end

-- 重置圣器相关信息
function resetHolyItemsLevel(classId)
    local holyItemsBase = ME.user.dbase:query("holy_items_level", "base", {});

    if holyItemsBase[classId] then
        holyItemsBase[classId] = 0;
    end
    ME.user.dbase:set("holy_items_level", "base", holyItemsBase);

    local extraLevelInfo = ME.user.dbase:query("holy_items_level", "extra", {});

    if extraLevelInfo[classId] then
        extraLevelInfo[classId] = 0;
    end

    ME.user.dbase:set("holy_items_level", "extra", extraLevelInfo);
end